\section{ДИАГРАММА КЛАССОВ}
\label{sec:apx1}

\begin{center}
    \includegraphics[scale=0.85]{img/classes}
\end{center}

\section{ИСХОДНЫЙ КОД}
\label{sec:apx2}

\subsubsection*{DecoderGC.h}

\tt\tiny
\begin{lstlisting}
#ifndef DECODERNC_H
#define DECODERNC_H

#include <newcode/ByteMatrix.h>
#include <newcode/encoder/EncoderGC.h>
#include <zxing/common/DecoderResult.h>

namespace newcode{
namespace decoder {

using namespace zxing;

class Decoder
{
private:
    int formatSize;
    bool formatIsString;
    int dimension;
    encoder::EncodeMode formatMode;
    Ref<ByteMatrix> theBytes;
    const static unsigned char MASK = 0xA8;
    const static float ERROR_CORECTION_LEVELS[];

    unsigned select2EqualFrom3(unsigned p1, unsigned p2, unsigned p3);
    ArrayRef<unsigned char> correctErrors(ArrayRef<unsigned char> codewordBytes,
        int numDataCodewords);

protected:
    ArrayRef<unsigned char> filterElement(ArrayRef<unsigned char> fromImage,
        encoder::EncodeMode mode);
    virtual void decodeFormatElements();
    virtual ArrayRef<unsigned char> decodeBytes();
    void getElementsFromImage(ArrayRef<unsigned char> elementsFromImage,
        int x, int y, bool isOdd = true);
    unsigned char selectFormatByte(int x, int y);
    int sizeWithECB(int size);

public:
     Ref<DecoderResult> decode(Ref<ByteMatrix> bytes);
};

}
}


#endif // DECODERNC_H
\end{lstlisting}

\subsubsection*{DecoderGC.cpp}

\tt\tiny
\begin{lstlisting}
#include "DecoderGC.h"
#include <cassert>
#include <zxing/FormatException.h>
#include <zxing/common/reedsolomon/ReedSolomonDecoder.h>
#include <zxing/common/reedsolomon/GF256.h>
#include <zxing/common/reedsolomon/ReedSolomonException.h>
#include <cmath>

#ifdef DEBUG
#include <iostream>
#endif

namespace newcode {
namespace decoder {

using namespace zxing;

const float Decoder::ERROR_CORECTION_LEVELS[] = {0.2, 0.4, 0.45, 0.25};

unsigned Decoder::select2EqualFrom3(unsigned p1, unsigned p2, unsigned p3)
{
    if (p1 == p2)
    {
        return p1;
    }
    else if (p1 == p3)
    {
        return p3;
    }
    else if (p2 == p3)
    {
        return p2;
    }
    else
    {
        return -1;
    }
}

Ref<DecoderResult> Decoder::decode(Ref<ByteMatrix> bytes)
{
    if (bytes->getX() != bytes->getY())
    {
        throw FormatException("Data matrix must be square");
    }

    if (bytes->getX() < 14)
    {
        throw FormatException("Matrix size too small");
    }

    if((bytes->getX() - 2) % 4 != 0 )
    {
        throw FormatException("Size of matrix must be devidable by 4");
    }

    theBytes = bytes;
    assert(sizeof(long) >= 4);
    decodeFormatElements();
    ArrayRef<unsigned char> rawBytes = decodeBytes();
    Ref<String> text;
    if (formatIsString)
    {
        text = Ref<String>(new String(string((const char*)&rawBytes[0],
            rawBytes.size())));
    }
    else
    {
        text = Ref<String>(NULL);
    }

    return Ref<DecoderResult>(new DecoderResult(rawBytes, text));
}

ArrayRef<unsigned char> Decoder::filterElement(
        ArrayRef<unsigned char> fromImage, encoder::EncodeMode mode)
{
    if (mode != encoder::ENCODE_MODE_3_LEVELS)
    {
        int bytesInElement = (int) mode + 1;
        ArrayRef<unsigned char> result(new unsigned char[bytesInElement],
            bytesInElement);
        long buffer = 0;
        float coreValue = 255.f / ((1 << bytesInElement) - 1);

        for (int i = 0; i < 8; i++)
        {
            buffer <<= bytesInElement;
            //add 0.5 to round
            buffer += (int)((255.f - fromImage[i]) / coreValue + 0.5);
        }

        for (int i = bytesInElement - 1; i >= 0; i--)
        {
            result[i] = (buffer & 0xFF) ^ MASK;
            buffer >>= 8;
        }

        return result;
    }
    else
    {
        ArrayRef<unsigned char> result(3);
        vector<int> digits(16);
        for (int i = 0; i < 16; i++)
        {
            digits[i] = (int)((255.f - fromImage[i]) / 127.5f + 0.5f);
        }
        int buf = 0;
        int power = 1;
        for (int i = 15; i >= 0; i--)
        {
            buf += power * digits[i];
            power *= 3;
        }

        for (int i = 2; i >= 0; i--)
        {
            result[i] = (buf & 0xFF) ^ MASK;
            buf >>= 8;
        }
        return result;
    }
}

void Decoder::decodeFormatElements()
{
    dimension = theBytes->getX() - 2;

    int size1 = selectFormatByte(1, 1) + (selectFormatByte(3, 1) << 8);
    int size2 = (selectFormatByte(1, dimension - 3) << 8) +
        selectFormatByte(1, dimension - 7);
    int size3 = (selectFormatByte(dimension - 1, dimension - 3) << 8) +
        selectFormatByte(dimension - 1, dimension - 7);

#   ifdef DEBUG
    std::cout << "decoded sizes " << dec <<size1 << ", " << size2 << ", " <<
        size3 << endl;
#   endif

    unsigned size = select2EqualFrom3(size1, size2, size3);
    if (size == (unsigned)-1 || size > 0xFFFF)
    {
        throw ReaderException("Could not detect size of code");
    }
    else
    {
        formatSize = (unsigned) size;
    }

    unsigned char coreByte1 = selectFormatByte(5, 1);
    unsigned char coreByte2 = selectFormatByte(3, dimension - 3);
    unsigned char coreByte3 = selectFormatByte(dimension - 3, dimension - 3);

#   ifdef DEBUG
    std::cout << "decoded core byte " << hex << (int)coreByte1 << ", " <<
        (int)coreByte2 << ", " << (int) coreByte3 << endl;
#   endif

    formatIsString = (bool)select2EqualFrom3(coreByte1 & 1,
        coreByte2 & 1, coreByte3 & 1);
    coreByte1 >>= 6;
    coreByte2 >>= 6;
    coreByte3 >>= 6;
    unsigned mode = select2EqualFrom3(coreByte1 & 3, coreByte2 & 3,
        coreByte3 & 3);
    if (mode == (unsigned) -1)
    {
         throw ReaderException("Could not detect mode of code");
    }
    else
    {
        formatMode = (encoder::EncodeMode) mode;
    }
}

ArrayRef<unsigned char> Decoder::decodeBytes()

{
    int sizeToRead = sizeWithECB(formatSize);
    ArrayRef<unsigned char> bytesFromImage(sizeToRead);
    int currentPointer = 0;
    int hieght = dimension / 4;
    int weigh = dimension / 2;
    bool finished = false;
    bool isOdd = true;
    ArrayRef<unsigned char> elementsFromImage(
        formatMode != encoder::ENCODE_MODE_3_LEVELS? 8: 16);
    for(int w = 0; w < weigh && !finished; w++)
    {
        for(int h = 0; h < hieght && !finished; h++)
        {
            int absoluteH =  4 * h + 1;
            int absoluteW = 2 * w + 1;

            bool isTopLeftCorner = (h == 0 && w < 3);
            bool isBottom1 = (h == hieght - 2 &&
                (w == 0 || w == weigh - 1));
            bool isBottom2 = (h == hieght - 1 && (w < 2 || w > weigh - 3));

            if (!(isTopLeftCorner || isBottom1 || isBottom2))
            {
                ArrayRef<unsigned char> bytes;

                if(formatMode != encoder::ENCODE_MODE_3_LEVELS)
                {
                    getElementsFromImage(elementsFromImage,
                        absoluteW, absoluteH);
                    bytes = filterElement(elementsFromImage, formatMode);
                }
                else
                {
                    if (isOdd)
                    {
                        getElementsFromImage(elementsFromImage, absoluteW,
                            absoluteH, isOdd);
                        isOdd = false;
                        continue;
                    }
                    else
                    {
                        getElementsFromImage(elementsFromImage, absoluteW,
                            absoluteH, isOdd);
                        bytes = filterElement(elementsFromImage, formatMode);
                        isOdd = true;
                    }

                }
                for(size_t i = 0; i < bytes.size() && !finished; i++)
                {
                    bytesFromImage[currentPointer++] = bytes[i];
                    if (currentPointer == sizeToRead)
                    {
                        finished = true;
                    }
                }
            }
        }
    }

    if (!finished)
    {
        throw FormatException("Code size doesn't match to matrix");
    }

#   ifdef DEBUG
    cout << "data read: ";
    for (size_t i = 0; i < bytesFromImage.size(); i++)
    {
        cout << (char) bytesFromImage[i] << "(" << hex <<
            (int) bytesFromImage[i] << ") ";
    }
    cout << endl;
#   endif

    return correctErrors(bytesFromImage, formatSize);
}

void Decoder:: getElementsFromImage(ArrayRef<unsigned char> elementsFromImage,
    int x, int y, bool isOdd)
{
    if (formatMode != encoder::ENCODE_MODE_3_LEVELS || isOdd)
    {
        for (int i = 0; i < 4; i++)
        {
            elementsFromImage[2 * i] = (*theBytes)(x, y + i);
            elementsFromImage[2 * i + 1] = (*theBytes)(x + 1, y + i);
        }
    }
    else
    {
        for (int i = 0; i < 4; i++)
        {
            elementsFromImage[2 * i + 8] = (*theBytes)(x, y + i);
            elementsFromImage[2 * i + 9] = (*theBytes)(x + 1, y + i);
        }
    }
}

int Decoder::sizeWithECB(int size)
{
    return 2 * ceil(ERROR_CORECTION_LEVELS[(int)formatMode] * size) + size;
}

unsigned char Decoder::selectFormatByte(int x, int y)
{
    ArrayRef<unsigned char> fromImage(8);
    getElementsFromImage(fromImage, x, y);
    return filterElement(fromImage, encoder::ENCODE_MODE_2_LEVELS)[0];
}

ArrayRef<unsigned char> Decoder::correctErrors(
    ArrayRef<unsigned char> codewordBytes, int numDataCodewords)
{
    int numCodewords = codewordBytes->size();
    ArrayRef<int> codewordInts(numCodewords);
    ArrayRef<unsigned char> result(numDataCodewords);
    for (int i = 0; i < numCodewords; i++)
    {
        codewordInts[i] = codewordBytes[i] & 0xff;
    }
    int numECCodewords = numCodewords - numDataCodewords;
    ReedSolomonDecoder rsDecoder(GF256::QR_CODE_FIELD);
    try
    {
        rsDecoder.decode(codewordInts, numECCodewords);
    }
    catch (ReedSolomonException const& ex)
    {
        ReaderException rex(ex.what());
        throw rex;
    }
    // Copy back into array of bytes -- only need to worry about the bytes that
    // were data. We don't care about errors in the error-correction codewords.
    for (int i = 0; i < numDataCodewords; i++)
    {
        result[i] = (unsigned char)codewordInts[i];
    }
    return result;
}

}
}

\end{lstlisting}

\subsubsection*{DetectorGC.h}

\tt\tiny
\begin{lstlisting}
#ifndef DETECTORNC_H
#define DETECTORNC_H

#include <zxing/common/Counted.h>
#include <zxing/common/DetectorResult.h>
#include <newcode/ByteMatrix.h>
#include <newcode/GreyscaleDetectorResult.h>
#include <zxing/LuminanceSource.h>
#include <zxing/datamatrix/detector/DetectorDM.h>

namespace newcode{
namespace detector{

using namespace zxing;

class Detector: public datamatrix::Detector
{
private:
    Ref<ByteMatrix> image_;
    unsigned char *dataBuffer;

    Ref<BitMatrix> binarize(Ref<ByteMatrix> matrix);
    inline static int round(float a);

protected:
    Ref<ByteMatrix> sampleGrid(Ref<ByteMatrix> image, int dimension,
        Ref<PerspectiveTransform> transform);

    static void correctContrast(Ref<ByteMatrix> image);

public:
    Detector(Ref<ByteMatrix> image);
    virtual ~Detector();
    Ref<GrayscaleDetectorResult> detect();
    Ref<ByteMatrix> getImage() const;
};

}
}

#endif // DETECTORNC_H
\end{lstlisting}

\subsubsection*{DetectorGC.cpp}

\tt\tiny
\begin{lstlisting}
#include "DetectorGC.h"
#include <zxing/common/GreyscaleLuminanceSource.h>
#include <zxing/common/detector/WhiteRectangleDetector.h>
#include <zxing/common/HybridBinarizer.h>
#include <newcode/GreyscaleGridSampler.h>

#include <cmath>

#ifdef DEBUG
#include <iostream>
#endif

namespace newcode{
namespace detector{

using namespace std;
Detector::Detector(Ref<ByteMatrix> image):
    datamatrix::Detector(binarize(image))
{
    image_ = image;
    //Now datamatrix::Detector holds binary variant of image
}

Ref<GrayscaleDetectorResult> Detector::detect()
{    
    Ref<WhiteRectangleDetector> rectangleDetector_(new WhiteRectangleDetector(
        datamatrix::Detector::getImage()));

    // The code below was copied from zxing::datamatrix::Detector::Detector from
    // ZXing project. Many thanx to them for this.
    std::vector<Ref<ResultPoint> > ResultPoints = rectangleDetector_->detect();
    Ref<ResultPoint> pointA = ResultPoints[0];
    Ref<ResultPoint> pointB = ResultPoints[1];
    Ref<ResultPoint> pointC = ResultPoints[2];
    Ref<ResultPoint> pointD = ResultPoints[3];

    // Point A and D are across the diagonal from one another,
    // as are B and C. Figure out which are the solid black lines
    // by counting transitions
    std::vector<Ref<datamatrix::ResultPointsAndTransitions> > transitions(4);
    transitions[0].reset(transitionsBetween(pointA, pointB));
    transitions[1].reset(transitionsBetween(pointA, pointC));
    transitions[2].reset(transitionsBetween(pointB, pointD));
    transitions[3].reset(transitionsBetween(pointC, pointD));
    insertionSort(transitions);

    // Sort by number of transitions. First two will be the two solid sides;
    // last two will be the two alternating black/white sides
    Ref<datamatrix::ResultPointsAndTransitions> lSideOne(transitions[0]);
    Ref<datamatrix::ResultPointsAndTransitions> lSideTwo(transitions[1]);

    // Figure out which point is their intersection by tallying up the number of
    // times we see the  endpoints in the four endpoints. One will show up
    // twice.
    Ref<ResultPoint> maybeTopLeft;
    Ref<ResultPoint> bottomLeft;
    Ref<ResultPoint> maybeBottomRight;
    if (lSideOne->getFrom()->equals(lSideOne->getTo())) {
      bottomLeft = lSideOne->getFrom();
      maybeTopLeft = lSideTwo->getFrom();
      maybeBottomRight = lSideTwo->getTo();
    } else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {
      bottomLeft = lSideOne->getFrom();
      maybeTopLeft = lSideOne->getTo();
      maybeBottomRight = lSideTwo->getTo();
    } else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {
      bottomLeft = lSideOne->getFrom();
      maybeTopLeft = lSideOne->getTo();
      maybeBottomRight = lSideTwo->getFrom();
    } else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {
      bottomLeft = lSideOne->getTo();
      maybeTopLeft = lSideOne->getFrom();
      maybeBottomRight = lSideTwo->getTo();
    } else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {
      bottomLeft = lSideOne->getTo();
      maybeTopLeft = lSideOne->getFrom();
      maybeBottomRight = lSideTwo->getFrom();
    } else {
      bottomLeft = lSideTwo->getFrom();
      maybeTopLeft = lSideOne->getTo();
      maybeBottomRight = lSideOne->getFrom();
    }

    // Bottom left is correct but top left and bottom right might be switched
    std::vector<Ref<ResultPoint> > corners(3);
    corners[0].reset(maybeTopLeft);
    corners[1].reset(bottomLeft);
    corners[2].reset(maybeBottomRight);

    // Use the dot product trick to sort them out
    ResultPoint::orderBestPatterns(corners);

    // Now we know which is which:
    Ref<ResultPoint> bottomRight(corners[0]);
    bottomLeft = corners[1];
    Ref<ResultPoint> topLeft(corners[2]);

    // Which point didn't we find in relation to the "L" sides? that's the top
    // right corner
    Ref<ResultPoint> topRight;
    if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) ||
          pointA->equals(topLeft))) {
      topRight = pointA;
    } else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft)
        || pointB->equals(topLeft))) {
      topRight = pointB;
    } else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft)
        || pointC->equals(topLeft))) {
      topRight = pointC;
    } else {
      topRight = pointD;
    }

    // Next determine the dimension by tracing along the top or right side and
    // counting black/white transitions. Since we start inside a black module,
    // we should see a number of transitions equal to 1 less than the code
    // dimension. Well, actually 2 less, because we are going to end on a black
    // module:

    // The top right point is actually the corner of a module, which is one of
    // the two black modules adjacent to the white module at the top right.
    // Tracing to that corner from either the top left or bottom right should
    // work here.

    int dimensionTop = transitionsBetween(topLeft, topRight)->getTransitions();
    int dimensionRight = transitionsBetween(bottomRight, topRight)->
            getTransitions();

    //dimensionTop++;
    if ((dimensionTop & 0x01) == 1) {
      // it can't be odd, so, round... up?
      dimensionTop++;
    }
    dimensionTop += 2;

    //dimensionRight++;
    if ((dimensionRight & 0x01) == 1) {
      // it can't be odd, so, round... up?
      dimensionRight++;
    }
    dimensionRight += 2;

    Ref<ByteMatrix> bytes;
    Ref<PerspectiveTransform> transform;
    Ref<ResultPoint> correctedTopRight;

    int dimension = min(dimensionRight, dimensionTop);

    // correct top right point to match the white module
    correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft,
                                        topRight, dimension);
    if (correctedTopRight == NULL) {
        correctedTopRight = topRight;
    }

    // Redetermine the dimension using the corrected top right point
    int dimensionCorrected = max(transitionsBetween(
        topLeft, correctedTopRight)->getTransitions(),
        transitionsBetween(bottomRight, correctedTopRight)->getTransitions());
    dimensionCorrected++;
    if ((dimensionCorrected & 0x01) == 1) {
        dimensionCorrected++;
    }

    transform = createTransform(topLeft, correctedTopRight, bottomLeft,
        bottomRight, dimensionCorrected, dimensionCorrected);
    bytes = sampleGrid(image_, dimensionCorrected, transform);
#   ifdef DEBUG
    cout << bytes->operator string() << *bytes;
#   endif
    correctContrast(bytes);
#   ifdef DEBUG
    cout << bytes->operator string() << *bytes;
#   endif
    std::vector<Ref<ResultPoint> > points(4);
    points[0].reset(topLeft);
    points[1].reset(bottomLeft);
    points[2].reset(correctedTopRight);
    points[3].reset(bottomRight);

    Ref<GrayscaleDetectorResult> detectorResult(
        new GrayscaleDetectorResult(bytes, points, transform));
    return detectorResult;
}

Ref<ByteMatrix> Detector::getImage() const
{
    return image_;
}

int  Detector::round(float a)
{
    return (int)(a + 0.5f);
}

//Should be called only once in constructor!
Ref<BitMatrix> Detector::binarize(
    Ref<ByteMatrix> matrix)
{
    int size = matrix->getX() * matrix->getY();
    dataBuffer = new unsigned char[size];
    int length = matrix->getX();
    for (int i = 0; i < matrix->getY(); i++)
    {
        memcpy(&dataBuffer[i * length], matrix->getRow(i), length);
    }
    Ref<GreyscaleLuminanceSource> result(new GreyscaleLuminanceSource(
        dataBuffer, matrix->getX(), matrix->getY(), 0, 0, matrix->getX(),
        matrix->getY()));
    HybridBinarizer hb(result);

    return hb.getBlackMatrix();
}

Ref<ByteMatrix> Detector:: sampleGrid(Ref<ByteMatrix> image, int dimension,
    Ref<PerspectiveTransform> transform)
{
    GreyscaleGridSampler &sampler = GreyscaleGridSampler::getInstance();
    return sampler.sampleGrid(image, dimension, transform);
}

void Detector::correctContrast(Ref<ByteMatrix> image)
{
    //We will apply linear ax + b trandormation to all pixel in image.
    int maxX = image->getX();
    int maxY = image->getY();
    unsigned char absoluteMin = 255;
    unsigned char absoluteMax = 0;
    unsigned char current = 0;

    for (int x = 0; x < maxX; x++)
    {
        for(int y = 0; y < maxY; y++)
        {
            current = (*image)(x, y);
            absoluteMax = current > absoluteMax? current: absoluteMax;
            absoluteMin = current < absoluteMin? current: absoluteMin;
        }
    }
    float a = 255.0f / (absoluteMax - absoluteMin);
    float b = - a * absoluteMin;

    for (int x = 0; x < maxX; x++)
    {
        for(int y = 0; y < maxY; y++)
        {
            current = (*image)(x, y);
            current = (unsigned char)round(a * current + b);
            (*image)(x, y) = (unsigned char)round(
                        255 * pow(current / 255.f, 1.1f));
        }
    }
}

Detector::~Detector()
{
    delete[] dataBuffer;
}

}
}
\end{lstlisting}

\subsubsection*{EncoderGC.h}

\tt\tiny
\begin{lstlisting}

#ifndef ENCODERNC_H
#define ENCODERNC_H

#include <newcode/ByteMatrix.h>
#include <zxing/common/Array.h>
#include <zxing/common/Str.h>

namespace newcode {
namespace encoder {
using namespace std;
using namespace zxing;

enum EncodeMode
{
    ENCODE_MODE_2_LEVELS,
    ENCODE_MODE_4_LEVELS,
    ENCODE_MODE_8_LEVELS,
    ENCODE_MODE_3_LEVELS
};

class Encoder
{
private:
    const static float ERROR_CORECTION_LEVELS[];
    const static unsigned char MASK = 0xA8;
    const static int FETCH_MASKS[];

    ArrayRef<unsigned char> data;
    EncodeMode encodeMode;
    ArrayRef<unsigned char> formatBytes;
    int sizeInBarsels;
    int initialDataSize;
    bool dataIsString;
    size_t pointer;

    //getNextElement3Levels() state variables.
    vector<int> digits;
    bool currentStateOdd;

public:
    Encoder();
    Ref<ByteMatrix> encode(String data,
        EncodeMode encodeMode = ENCODE_MODE_4_LEVELS);
    Ref<ByteMatrix> encode(ArrayRef<unsigned char> data,
        EncodeMode encodeMode = ENCODE_MODE_4_LEVELS);

private:
    inline int messageSize();
    void computeSizeInBarsels();
    void setupFormatData();
    Ref<ByteMatrix> buidMatrix();
    inline ArrayRef<unsigned char> getFormatElement(int index);
    inline ArrayRef<unsigned char> getNextElement();
    ArrayRef<unsigned char> getNextElement3Levels();
    void setBarsels(Ref<ByteMatrix> matrix, int h, int w,
        ArrayRef<unsigned char> barsels);
    inline unsigned char getNextMaskedByte();
    unsigned char barselForValue(int value) const;
    inline float positiveRound(float value) const;
    ArrayRef<unsigned char> addErrorCorrectionBytes(
        const ArrayRef<unsigned char> initialData);
    static vector<int> toTernarSystem(int val);
};

}
}

#endif // ENCODERNC_H
\end{lstlisting}

\subsubsection*{EncoderGC.cpp}

\tt\tiny
\begin{lstlisting}
#include "EncoderGC.h"
#include <cmath>
#include <cassert>
#include <cstdlib>
#include <zxing/common/IllegalArgumentException.h>
#include <newcode/ReedSolomonEncoder.h>


namespace newcode {
namespace encoder {

const int Encoder::FETCH_MASKS[] = {1, 3, 7};

const float Encoder::ERROR_CORECTION_LEVELS[] = {0.2, 0.4, 0.45, 0.25};

Encoder::Encoder(): dataIsString(false), pointer(0) {}

Ref<ByteMatrix> Encoder::encode(String data, EncodeMode encodeMode)
{
    ArrayRef<unsigned char> stringData = ArrayRef<unsigned char>(
        (unsigned char*)data.getText().data(), data.getText().size());
    dataIsString = true;
    return encode(stringData, encodeMode);
}

Ref<ByteMatrix> Encoder::encode(ArrayRef<unsigned char> data,
        EncodeMode encodeMode)
{
    //check if long holds at least 4 bytes.
    assert(sizeof(long) >= 4);
    this->currentStateOdd = true;
    this->initialDataSize = data.size();
    this->encodeMode = encodeMode;
    this->data = addErrorCorrectionBytes(data);
    if (initialDataSize > 0xFFFF)
    {
        throw IllegalArgumentException("Too large data to encode");
    }
    computeSizeInBarsels();
    setupFormatData();
    return buidMatrix();
}

int Encoder::messageSize()
{
    return 2 * ceil(ERROR_CORECTION_LEVELS[(int)encodeMode] *
                    initialDataSize) + initialDataSize;
}

void Encoder::computeSizeInBarsels()
{
    int dataCells;
    if (encodeMode != ENCODE_MODE_3_LEVELS)
    {
        dataCells = ceil((double) messageSize() / (encodeMode + 1));
    }
    else
    {
        dataCells = ceil((double) messageSize() / 1.5);
    }
    sizeInBarsels = ceil(sqrt((double)((dataCells + 9 + 1) >> 1))) * 4;
}

void Encoder::setupFormatData()
{
    formatBytes = ArrayRef<unsigned char>(3);
    formatBytes[0] = initialDataSize & 0xFF;
    formatBytes[1] = (initialDataSize & 0xFF00) >> 8;
    int isString = dataIsString? 1: 0;
    formatBytes[2] = ((int)encodeMode << 6) + isString;
}

Ref<ByteMatrix> Encoder::buidMatrix()
{
    Ref<ByteMatrix> result = Ref<ByteMatrix>(new ByteMatrix(sizeInBarsels + 2,
        sizeInBarsels + 2));
    for(int i = 0; i < sizeInBarsels + 2; i++)
    {
        (*result)(i, 0) = 0;
        (*result)(sizeInBarsels + 1, i) = 0;
        (*result)(0, i) = (i % 2 == 0)? 0: 255;
        (*result)(i, sizeInBarsels + 1) = (i % 2 == 1)? 0:255;
    }

    int hieght = sizeInBarsels / 4;
    int weigh = sizeInBarsels / 2;
    for(int w = 0; w < weigh; w++)
    {
        for(int h = 0; h < hieght; h++)
        {
            int absoluteH =  4 * h + 1;
            int absoluteW = 2 * w + 1;
            //left top corner of format
            if (h == 0 && w < 3)
            {
                setBarsels(result, absoluteH, absoluteW, getFormatElement(w));
            }
            else if (h == hieght - 2 && (w == 0 || w == weigh - 1))
            {
                setBarsels(result, absoluteH, absoluteW, getFormatElement(0));
            }
            else if (h == hieght - 1 && (w < 2 || w > weigh - 3))
            {
                if (w == 0 || w == weigh - 1)
                {
                    setBarsels(result, absoluteH, absoluteW,
                        getFormatElement(1));
                }
                else
                {
                    setBarsels(result, absoluteH, absoluteW,
                        getFormatElement(2));
                }
            } else {
                setBarsels(result, absoluteH, absoluteW, getNextElement());
            }
        }
    }

    return result;
}

ArrayRef<unsigned char> Encoder::getFormatElement(int index)
{
    ArrayRef<unsigned char> result(8);
    unsigned char byte = formatBytes[index] ^ MASK;
    for(int i = 7; i >= 0; i--)
    {
        result[i] = ((byte & 0x01) == 1)? 0: 255;
        byte >>= 1;
    }

    return result;
}

void Encoder::setBarsels(Ref<ByteMatrix> matrix, int h, int w,
    ArrayRef<unsigned char> barsels)
{
    for (int i = 0; i < 4; i++)
    {
        (*matrix)(h + i, w) = barsels[2 * i];
        (*matrix)(h + i, w + 1) = barsels[2 * i + 1];
    }
}

unsigned char Encoder::getNextMaskedByte()
{
    if (pointer < data.size())
    {
        return data[pointer++] ^ MASK;
    }
    else
    {
        return rand() ^ MASK;
    }
}

ArrayRef<unsigned char> Encoder::getNextElement()
{
    if (encodeMode != ENCODE_MODE_3_LEVELS)
    {
        ArrayRef<unsigned char> result(8);
        int bytesCount = (int)encodeMode + 1;
        long word = 0;
        for (int i = 0; i < bytesCount; i++)
        {
            word <<= 8;
            word |= getNextMaskedByte();
        }
        for(int i = 7; i >= 0; i--)
        {
            int val = word & FETCH_MASKS[bytesCount - 1];
            result[i] = barselForValue(val);
            word >>= (int)encodeMode + 1;
        }
        return result;
    }
    else
    {
        return getNextElement3Levels();
    }
}

ArrayRef<unsigned char> Encoder::getNextElement3Levels()
{
    ArrayRef<unsigned char> result(8);

    int index = 0, end = 0;
    if(currentStateOdd)
    {
        int buf = getNextMaskedByte() & 0xFF;
        buf <<= 8;
        buf |= getNextMaskedByte() & 0xFF;
        buf <<= 8;
        buf |= getNextMaskedByte() & 0xFF;
        digits = toTernarSystem(buf);
        index = 0;
        currentStateOdd = false;
    }
    else
    {
        index = 8;
        currentStateOdd = true;
    }
    end = index + 8;
    int i = 0;
    for (; index < end; index++)
    {
        result[i++] = barselForValue(digits[index]);
    }
    return result;
}

unsigned char Encoder::barselForValue(int value) const
{
    if (encodeMode != ENCODE_MODE_3_LEVELS)
    {
        float delta = 255.0f / ((2 << encodeMode) - 1);
        int h = (int)positiveRound(delta * value);
        return static_cast<unsigned char>(255 - h);
    }
    else
    {
        unsigned char greyVals[] = {255, 127, 0};
        return greyVals[value];
    }
}

float Encoder::positiveRound(float value) const
{
    return floor(value + 0.5f);
}

ArrayRef<unsigned char> Encoder::addErrorCorrectionBytes(
    const ArrayRef<unsigned char> initialData)
{
    ReedSolomonEncoder rse(GF256::QR_CODE_FIELD);
    size_t msgSize = messageSize();
    ArrayRef<int> toEncode(msgSize);
    for (size_t i = 0; i < msgSize; i++)
    {
        if (i < initialData.size()) {
            toEncode[i] = initialData[i];
        }
        else
        {
            toEncode[i] = 0;
        }
    }
    rse.encode(toEncode, msgSize - initialData.size());
    ArrayRef<unsigned char> res(msgSize);
    for (size_t i = 0; i < msgSize; i++)
    {
        res[i] = toEncode[i];
    }
    return res;
}

vector<int> Encoder::toTernarSystem(int val)
{
    vector<int> result(16);
    for (int i = 0; i < 16; i++)
    {
        result[15 - i] = val % 3;
        val /= 3;
    }
    return result;
}

}
}
\end{lstlisting}

\subsubsection*{PerspectiveTransform.h}
\label{sec:perTransform}
\tt\tiny
\begin{lstlisting}
#ifndef __PERSPECTIVE_TANSFORM_H__
#define __PERSPECTIVE_TANSFORM_H__

/*
 *  PerspectiveTransform.h
 *  zxing
 *
 *  Copyright 2010 ZXing authors All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <zxing/common/Counted.h>
#include <vector>

namespace zxing {
class PerspectiveTransform : public Counted {
private:
  float a11, a12, a13, a21, a22, a23, a31, a32, a33;
  PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, float a23,
                       float a33);

public:
  static Ref<PerspectiveTransform>
  quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3,
                               float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p);
  static Ref<PerspectiveTransform> squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2,
      float x3, float y3);
  static Ref<PerspectiveTransform> quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2,
      float x3, float y3);
  Ref<PerspectiveTransform> buildAdjoint();
  Ref<PerspectiveTransform> times(Ref<PerspectiveTransform> other);
  void transformPoints(std::vector<float> &points);

  friend std::ostream& operator<<(std::ostream& out, const PerspectiveTransform &pt);
};
}

#endif // __PERSPECTIVE_TANSFORM_H__
\end{lstlisting}

\subsubsection*{PerspectiveTransform.cpp}

\tt\tiny
\begin{lstlisting}
/*
 *  PerspectiveTransform.cpp
 *  zxing
 *
 *  Created by Christian Brunschen on 12/05/2008.
 *  Copyright 2008 Google UK. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <zxing/common/PerspectiveTransform.h>

namespace zxing {
using namespace std;

PerspectiveTransform::PerspectiveTransform(float inA11, float inA21, 
                                           float inA31, float inA12, 
                                           float inA22, float inA32, 
                                           float inA13, float inA23, 
                                           float inA33) : 
  a11(inA11), a12(inA12), a13(inA13), a21(inA21), a22(inA22), a23(inA23),
  a31(inA31), a32(inA32), a33(inA33) {}

Ref<PerspectiveTransform> PerspectiveTransform::quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1,
    float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p,
    float x3p, float y3p) {
  Ref<PerspectiveTransform> qToS = PerspectiveTransform::quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
  Ref<PerspectiveTransform> sToQ =
    PerspectiveTransform::squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
  return sToQ->times(qToS);
}

Ref<PerspectiveTransform> PerspectiveTransform::squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2,
    float y2, float x3, float y3) {
  float dy2 = y3 - y2;
  float dy3 = y0 - y1 + y2 - y3;
  if (dy2 == 0.0f && dy3 == 0.0f) {
    Ref<PerspectiveTransform> result(new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f,
                                     0.0f, 1.0f));
    return result;
  } else {
    float dx1 = x1 - x2;
    float dx2 = x3 - x2;
    float dx3 = x0 - x1 + x2 - x3;
    float dy1 = y1 - y2;
    float denominator = dx1 * dy2 - dx2 * dy1;
    float a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
    float a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
    Ref<PerspectiveTransform> result(new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0
                                     + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0f));
    return result;
  }
}

Ref<PerspectiveTransform> PerspectiveTransform::quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2,
    float y2, float x3, float y3) {
  // Here, the adjoint serves as the inverse:
  return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3)->buildAdjoint();
}

Ref<PerspectiveTransform> PerspectiveTransform::buildAdjoint() {
  // Adjoint is the transpose of the cofactor matrix:
  Ref<PerspectiveTransform> result(new PerspectiveTransform(a22 * a33 - a23 * a32, a23 * a31 - a21 * a33, a21 * a32
                                   - a22 * a31, a13 * a32 - a12 * a33, a11 * a33 - a13 * a31, a12 * a31 - a11 * a32, 
                                   a12 * a23 - a13 * a22,
                                   a13 * a21 - a11 * a23, a11 * a22 - a12 * a21));
  return result;
}

Ref<PerspectiveTransform> PerspectiveTransform::times(Ref<PerspectiveTransform> other) {
  Ref<PerspectiveTransform> result(new PerspectiveTransform(a11 * other->a11 + a21 * other->a12 + a31 * other->a13,
                               a11 * other->a21 + a21 * other->a22 + a31 * other->a23, a11 * other->a31 + a21 * other->a32 + a31
                                   * other->a33, a12 * other->a11 + a22 * other->a12 + a32 * other->a13, a12 * other->a21 + a22
                                   * other->a22 + a32 * other->a23, a12 * other->a31 + a22 * other->a32 + a32 * other->a33, a13
                                   * other->a11 + a23 * other->a12 + a33 * other->a13, a13 * other->a21 + a23 * other->a22 + a33
                                   * other->a23, a13 * other->a31 + a23 * other->a32 + a33 * other->a33));
  return result;
}

void PerspectiveTransform::transformPoints(vector<float> &points) {
  int max = points.size();
  for (int i = 0; i < max; i += 2) {
    float x = points[i];
    float y = points[i + 1];
    float denominator = a13 * x + a23 * y + a33;
    points[i] = (a11 * x + a21 * y + a31) / denominator;
    points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
  }
}

ostream& operator<<(ostream& out, const PerspectiveTransform &pt) {
  out << pt.a11 << ", " << pt.a12 << ", " << pt.a13 << ", \n";
  out << pt.a21 << ", " << pt.a22 << ", " << pt.a23 << ", \n";
  out << pt.a31 << ", " << pt.a32 << ", " << pt.a33 << "\n";
  return out;
}

}

\end{lstlisting}